using System.Collections.Generic;
using System.IO.Compression;
using System;
using System.Linq;
using UMC.SshNet;
using UMC.Web;
using UMC.Web.UI;
using UMC.Net;
using UMC.Security;
using System.IO;
using UMC.ITME.Entities;
using UMC.Bridge;
using System.Net.Sockets;
using System.Formats.Cbor;
// using System.Net;
// using System.Net;

namespace UMC.ITME.Activities;


[Apiumc("ITME", "SSH", Auth = WebAuthType.User)]
class SiteSSHActivities : Web.WebActivity
{

    public static void SSHLog(Entities.Device device, String Username, StringValue ip, StringValue userAgent, StringValue Referer, params string[] logs)
    {
        var loger = new HttpLoger(new ByteChunk());
        loger.Write(HttpLogerType.IP, ip);
        loger.Write(HttpLogerType.Username, Username);
        loger.Write(HttpLogerType.Host, $"{device.Username}@{device.Ip}");
        loger.Write(HttpLogerType.Path, logs[0]);
        loger.Write(HttpLogerType.Referer, Referer);
        loger.Write(HttpLogerType.UserAgent, userAgent);
        if (logs.Length > 1)
        {
            loger.Info().Write(String.Join("\r\n", logs.AsSpan(1).ToArray())).End();
        }
        HttpLogerDoWorker.AppendLog(loger);
    }
    public static void SSHLog(NetContext context, Entities.Device device, params string[] logs)
    {

        if (System.Net.IPAddress.TryParse(context.UserHostAddress, out var v))
        {
            SSHLog(device, context.Token.Username, new StringValue(v.GetAddressBytes()), context.Headers.Get(StringValue.Referer.Span), context.UserAgent, logs);
        }
    }
    public override void ProcessActivity(WebRequest request, WebResponse response)
    {
        var Key = this.AsyncDialog("Key", g =>
        {
            var form = request.SendValues ?? new WebMeta();
            var limit = form["limit"] ?? "none";

            var user = this.Context.Token.Identity();
            var searcher = UMC.Data.HotCache.Search<Entities.Device>();

            var Keyword = form["Keyword"];

            if (String.IsNullOrEmpty(Keyword) == false)
            {
                searcher.Or().Like(new Entities.Device { Caption = Keyword, Ip = Keyword, Username = Keyword, Desc = Keyword });
            }
            switch (limit)
            {
                case "PC":
                    {

                        var GroupKey = Utility.IntParse(this.AsyncDialog("GroupKey", "-1"), -1);
                        var sts = new System.Data.DataTable();
                        sts.Columns.Add("id");
                        sts.Columns.Add("ip");
                        sts.Columns.Add("caption");
                        sts.Columns.Add("user");
                        sts.Columns.Add("port");
                        sts.Columns.Add("report");
                        sts.Columns.Add("type");

                        var ds = searcher.Query(new Entities.Device(), false, 0, 1500, out var index);
                        if (GroupKey > -1)
                        {
                            ds = ds.Where(r => (r.GroupKey ?? 0) == GroupKey).ToArray();
                        }
                        switch (request.SendValues?.Get("field") ?? String.Empty)
                        {
                            case "caption":
                                ds = (String.Equals(request.SendValues?.Get("sort"), "desc") ? ds.OrderByDescending(s => s.Caption) : ds.OrderBy(s => s.Caption)).ToArray();
                                break;
                            case "ip":
                                ds = (String.Equals(request.SendValues?.Get("sort"), "desc") ? ds.OrderByDescending(s => s.Ip) : ds.OrderBy(s => s.Ip)).ToArray();
                                break;
                            case "user":
                                ds = (String.Equals(request.SendValues?.Get("sort"), "desc") ? ds.OrderByDescending(s => s.Username) : ds.OrderBy(s => s.Username)).ToArray();
                                break;
                            default:

                                break;
                        }

                        var auths = UMC.Security.AuthManager.Authorization(user, 0, ds.Select(r => new StringValue($"Device/{r.Id}")).ToArray());
                        var count = 0; int i = 0;
                        foreach (var d in ds)
                        {
                            if (auths[i].Item1 > 0)
                            {
                                count++;
                                sts.Rows.Add(d.Id, d.Ip, d.Caption, d.Username, d.Port, BitConverter.ToUInt16(d.Id.Value.StringValue().Span.Slice(6)), d.Type ?? Entities.DeviceType.Tcp);
                            }
                            i++;
                        }
                        var rdata = new WebMeta().Put("data", sts);

                        if (count == 0)
                        {
                            if (String.IsNullOrEmpty(Keyword))
                            {
                                rdata.Put("msg", "未有可访问的设备");
                            }
                            else
                            {
                                rdata.Put("msg", $"未搜索到“{Keyword}”相关可访问的设备");
                            }

                        }
                        if (GroupKey == -1)
                        {
                            this.Context.Send("WebSSH", request.IsMaster ? rdata.Put("IsMaster", true) : rdata, true);

                        }
                        else
                        {
                            response.Redirect(request.IsMaster ? rdata.Put("IsMaster", true) : rdata);
                        }
                    }
                    break;
                default:
                    {
                        var title = UITitle.Create();

                        title.Title = "我的设备";

                        var ds = searcher.Query(new Entities.Device(), false, 0, 1500, out var index);

                        var auths = UMC.Security.AuthManager.Authorization(user, 0, ds.Select(r => new StringValue($"Device/{r.Id}")).ToArray());
                        if (request.IsMaster)
                            title.Right(new UIEventText().Icon('\ue907').Click(new UIClick(request, g, "Create")));
                        var ui = UISection.Create(title);
                        var webr = UMC.Data.WebResource.Instance();
                        var count = 0;
                        int i = 0;
                        foreach (var d in ds)
                        {
                            if (auths[i].Item1 > 0)
                            {
                                char icon = '\uf17c';
                                switch (d.Type)
                                {
                                    case DeviceType.Tcp:
                                        icon = '\uf1c0';
                                        break;
                                    case DeviceType.Rdp:
                                        icon = '\uf17a';
                                        break;
                                }
                                var item = new UIIconNameDesc.Item(icon, d.Caption, $"{d.Username}@{d.Ip}");
                                count++;
                                UIIconNameDesc uIIcon = new UIIconNameDesc(item);
                                item.Color(0x111);
                                item.Click(new UIClick(request, g, d.Id.ToString()));
                                if (request.IsMaster)
                                {
                                    ui.Delete(uIIcon, new UIEventText("删除").Click(new UIClick(request, g, d.Id.ToString(), "Model", "Remove")));
                                }
                                else
                                {
                                    ui.Add(uIIcon);
                                }
                            }
                            i++;
                        }
                        if (count == 0)
                        {
                            if (String.IsNullOrEmpty(Keyword))
                            {
                                var desc = new UIDesc("未有可访问的设备");
                                desc.Put("icon", "\uf016").Format("desc", "{icon}\n{desc}");
                                desc.Style.Align(1).Color(0xaaa).Padding(20, 20).BgColor(0xfff).Size(12).Name("icon", new UIStyle().Font("wdk").Size(60));
                                ui.Add(desc);
                            }
                            else
                            {
                                var desc = new UIDesc($"未搜索到“{Keyword}”相关可访问的设备");
                                desc.Put("icon", "\uf016").Format("desc", "{icon}\n{desc}");
                                desc.Style.Align(1).Color(0xaaa).Padding(20, 20).BgColor(0xfff).Size(12).Name("icon", new UIStyle().Font("wdk").Size(60));
                                ui.Add(desc);
                            }
                        }
                        ui.SendTo(this.Context, $"{request.Model}.{request.Command}");
                    }
                    break;
            }


            return this.DialogValue("none");
        });
        switch (Key)
        {
            case "Create":
                Create();
                break;
        }
        var device = UMC.Data.HotCache.Get(new Entities.Device { Id = Utility.UInt64Parse(Key, 0L) });
        if (Security.AuthManager.Authorization(this.Context.Token.Identity(), 0, new Net.StringValue($"Device/{device.Id}"), out var isBiometric) > 0)
        {
            if (isBiometric)
            {
                this.AsyncDialog("Biometric", "System", "Biometric", true);
            }
        }
        else
        {
            this.Prompt("您未有权限访问此设备资源");
        }
        var model = this.AsyncDialog("Model", g =>
        {
            int start = UMC.Data.Utility.IntParse(request.SendValues?["start"] as string, 0);
            var nextKey = request.SendValues?["NextKey"] ?? "Header";

            UISection ui = null;
            UISection pathUI = null;
            if (start == 0 && String.Equals(nextKey, "Header"))
            {
                ui = UISection.Create(new UITitle("资源设备"));
                if (request.IsMaster)
                {
                    ui.AddCell("设备名称", device.Caption, new UIClick(request, g, "Editer"));
                    // ui.Delete(uIIcon, new UIEventText("删除").Click(new UIClick(request, g, Key, "Model", "Remove")));
                }
                else
                {
                    ui.AddCell("设备名称", device.Caption);
                }
                var port = BitConverter.ToUInt16(device.Id.Value.StringValue().Span.Slice(6));// & 0xffff;

                var cell = UI.UI("网址端口", $"{device.Ip}:{device.Port}");
                ui.Add(cell);
                if (port != (ushort)device.Port.Value)
                {
                    ui.AddCell("发布端口", $"{port}");
                }
                // switch()
                // if (device.Type == Entities.DeviceType.Socket)
                // {
                //     ui.AddCell("用户名", device.Username);
                // }
                if (device.Type == Entities.DeviceType.Ssh || device.Type == Entities.DeviceType.Rdp)
                {
                    ui.AddCell("用户名", device.Username);
                }

                if (String.IsNullOrEmpty(device.Desc) == false)
                {
                    ui.AddCell("描述", device.Desc);
                }
                if (request.IsMaster)
                {
                    ui.AddCell("设置权限", new UIClick("Settings", "AuthKey", new WebMeta().Put("Key", $"Device/{device.Id}")));

                }
                if (device.Type == Entities.DeviceType.Tcp)
                {
                    var password = UMC.Data.DataFactory.Instance().Password(SiteConfig.MD5Key(device.Id.ToString(), device.Username));
                    ui.NewSection().AddCell("资源用户", "点击复制", new UIClick(device.Username) { Key = "Copy" })
                    .AddCell("资源密码", "点击复制", new UIClick(password) { Key = "Copy" });
                }
                pathUI = ui.NewSection();

            }
            else
            {
                ui = pathUI = UISection.Create();
            }
            if (device.Type == DeviceType.Ssh)
            {
                pathUI.Key = "Path";
                var path = this.AsyncDialog("Path", "/");
                var password = UMC.Data.DataFactory.Instance().Password(SiteConfig.MD5Key(device.Id.ToString(), device.Username));
                try
                {
                    using (var sftp = new SftpClient(new PasswordConnectionInfo(device.Ip, device.Port ?? 22, device.Username, password)))
                    {
                        sftp.Connect();
                        var sftpFiles = sftp.ListDirectory(path).Where(f => f.Name != "." && f.Name != "..");
                        if (String.Equals(path, "/"))
                        {
                            pathUI.AddCell('\uf0e8', "根目录", "/");
                        }
                        else
                        {
                            var name = path.LastIndexOf('/', path.Length - 1);
                            var parentPath = path.Substring(0, name);
                            var click = request.IsApp ? UIClick.Query("Path", new WebMeta("Path", String.IsNullOrEmpty(parentPath) ? "/" : parentPath)) : UIClick.UIEvent("Search", new WebMeta("key", "Path").Put("search", new WebMeta("Path", path.Substring(0, name))));// UIClick.Click(new UIClick(request, "Path", path.Substring(0, name), "Model", "Next"));
                            if (sftpFiles.Count() == 0)
                            {
                                var cell = UICell.Create("UI", new WebMeta("value", path.Substring(name + 1)).Put("text", "当前目录").Put("Icon", '\uf0e8').Put("click", click));
                                pathUI.Delete(cell, new UIEventText("删除").Click(UIClick.Click(new UIClick(request, g, "Del", "Path", path + "/"))));

                                var desc = new UIDesc($"当前目录没有文件或子目录");
                                desc.Put("icon", "\uf016").Format("desc", "{icon}\n{desc}");
                                desc.Style.Align(1).Color(0xaaa).Padding(20, 20).BgColor(0xfff).Size(12).Name("icon", new UIStyle().Font("wdk").Size(60));
                                pathUI.Add(desc);
                            }
                            else
                            {
                                pathUI.AddCell('\uf0e8', "当前目录", path.Substring(name + 1), click);
                            }
                        }
                        var dirs = sftpFiles.Where(r => r.IsDirectory).OrderByDescending(r => r.Name);
                        var files = sftpFiles.Where(r => r.IsDirectory == false).OrderByDescending(r => r.Name);
                        foreach (var file in dirs)
                        {

                            pathUI.AddCell('\uf114', file.Name, "", request.IsApp ? UIClick.Query("Path", new WebMeta("Path", file.FullName)) : UIClick.UIEvent("Search", new WebMeta("key", "Path").Put("search", new WebMeta("Path", file.FullName))));// ("Path", file.FullName)));

                        }
                        foreach (var file in files)
                        {
                            var cell = UICell.Create("UI", new WebMeta("value", Utility.GetBitSize(file.Length)).Put("text", file.Name).Put("Icon", '\uf0f6').Put("click", new UIClick(request, g, file.Length > 1000000 ? "Down" : "View", "Path", file.FullName)));
                            pathUI.Delete(cell, new UIEventText("删除").Click(new UIClick(request, g, "Del", "Path", file.FullName)));
                        }
                    }
                }
                catch (Exception ex)
                {
                    var desc = new UIDesc(ex.Message);
                    desc.Put("icon", "\uf016").Format("desc", "{icon}\n{desc}");
                    desc.Style.Align(1).Color(0xaaa).Padding(20, 20).BgColor(0xfff).Size(12).Name("icon", new UIStyle().Font("wdk").Size(60));
                    pathUI.Add(desc);
                }
                ui.UIFootBar = new UIFootBar() { IsFixed = true };
                if (request.IsApp)
                {
                    ui.UIFootBar.AddIcon(new UIEventText('\uf2d0', "终端").Click(new UIClick(request, g, "Open")));
                }
                else
                {
                    ui.UIFootBar.AddIcon(new UIEventText('\uf122', "展开").Click(new UIClick(request, g, "Open")));
                }

                ui.UIFootBar.AddIcon(new UIEventText('\uf0ee', "上传").Click(new UIClick(request, g, "UploadFile")));
                if (String.Equals(path, "/") == false)
                {
                    ui.UIFootBar.AddIcon(new UIEventText('\uf019', "压缩").Click(new UIClick(request, g, "OpenFile", "Type", "3")));
                }
                ui.UIFootBar.AddText(new UIEventText("新建文件").Click(new UIClick(request, g, "NewFile")),
                 new UIEventText("新建目录").Click(new UIClick(request, g, "New")).Style(new UIStyle().BgColor()));
            }
            else
            {
                var ids = BitConverter.GetBytes(device.Id.Value);
                ids.AsSpan(6).Reverse();
                var idsValue = System.Buffers.ArrayPool<byte>.Shared.Rent(4096);


                var t = Utility.TimeSpan().StringValue();
                t.Span.Reverse();

                t.Span.CopyTo(idsValue);
                WebServlet.AppId.Span.CopyTo(idsValue.AsSpan(4));
                WebServlet.AppSecret.Span.CopyTo(idsValue.AsSpan(20));
                Utility.MD5(idsValue.AsSpan(0, 36), idsValue.AsSpan(7));
                t.Span.CopyTo(idsValue.AsSpan(3));

                idsValue[0] = 0x06;
                idsValue[1] = 0x01;
                idsValue[2] = 20;

                idsValue[23] = 6;
                ids.AsSpan(2).CopyTo(idsValue.AsSpan(24));

                idsValue[30] = 0x00;


                try
                {
                    using (var tcpClient = new TcpClient())
                    {
                        tcpClient.Connect("127.0.0.1", 443);
                        using (var stream = tcpClient.GetStream())
                        {
                            stream.Write(idsValue.AsSpan(0, 31));
                            int size = stream.Read(idsValue);
                            var reader = new CborReader(idsValue.AsMemory(0, size));
                            int length = reader.ReadStartArray() ?? 0;

                            if (length == 0)
                            {
                                var desc = new UIDesc("还未有授权日志");
                                desc.Put("icon", "\uf016").Format("desc", "{icon}\n{desc}");
                                desc.Style.Align(1).Color(0xaaa).Padding(20, 20).BgColor(0xfff).Size(12).Name("icon", new UIStyle().Font("wdk").Size(60));
                                pathUI.Add(desc);
                            }
                            else
                            {
                                for (int i = 0; i < length; i++)
                                {
                                    int cells = reader.ReadStartArray() ?? 0;
                                    var ip = reader.ReadByteString();
                                    var userName = reader.ReadTextString();
                                    var time = (uint)reader.ReadInt64();//. as uint;

                                    reader.ReadEndArray();
                                    switch (ip.Length)
                                    {
                                        case 8:
                                        case 20:
                                            var address = new System.Net.IPAddress(ip.AsSpan(0, ip.Length - 4));
                                            pathUI.Add(UI.UI(userName.Split('@').First(), address.ToString(), Utility.GetDate(Utility.TimeSpan(time))));
                                            break;
                                    }
                                }

                            }

                            reader.ReadEndArray();

                        }
                    }
                }
                finally
                {
                    System.Buffers.ArrayPool<byte>.Shared.Return(idsValue);
                }

                // var sockUsers = SocksUser.Cache.Find(new SocksUser { UserAgent = new StringValue(ids, 2, 4), Port = new StringValue(ids, 6, 2) }, 0, out var _);
                // if (sockUsers.Length == 0)
                // {

                //     var desc = new UIDesc("还未有授权日志");
                //     desc.Put("icon", "\uf016").Format("desc", "{icon}\n{desc}");
                //     desc.Style.Align(1).Color(0xaaa).Padding(20, 20).BgColor(0xfff).Size(12).Name("icon", new UIStyle().Font("wdk").Size(60));
                //     pathUI.Add(desc);
                // }
                // else
                // {
                //     foreach (var user in sockUsers)
                //     {
                //         switch (user.ClientIP.Length)
                //         {
                //             case 8:
                //             case 20:
                //                 var address = new System.Net.IPAddress(user.ClientIP.Span.Slice(0, user.ClientIP.Length - 4));
                //                 pathUI.Add(UI.UI(user.Username.ToString(), address.ToString(), Utility.GetDate(Utility.TimeSpan(user.ActiveTime.UInt32() ?? 0))));
                //                 break;
                //         }
                //     }
                // }

                ui.UIFootBar = new UIFootBar() { IsFixed = true };
                ui.UIFootBar.AddText(new UIEventText("生成代理参数").Click(new UIClick(request, g, "Proxy")),
                 new UIEventText("映射此资源").Click(new UIClick(request, g, "Mapper")).Style(new UIStyle().BgColor()));
            }
            ui.SendTo($"OpenPath,UploadFile,{request.Model}.{request.Command}.Remove", this.Context, $"{request.Model}.{request.Command}");

        });
        var Path = this.AsyncDialog("Path", "/");
        var password = UMC.Data.DataFactory.Instance().Password(SiteConfig.MD5Key(device.Id.ToString(), device.Username));
        //
        switch (model)
        {
            case "Next":
                {
                    var webMeta = new WebMeta(request.Arguments);

                    webMeta.Remove("Model");
                    this.Context.Send("ViewPath", new WebMeta().Put("Path", Path), false);
                    this.Context.UIEvent("Search", this.AsyncDialog("UI", "none"), new WebMeta("key", "Path").Put("search", webMeta), true);

                }
                break;
            case "Mapper":
                {
                    var user = System.Buffers.ArrayPool<byte>.Shared.Rent(520);
                    try
                    {
                        var size = this.Context.Token.Username.WriteBytes(user, 0);

                        var ms = user.AsSpan(size, 16);
                        Utility.MD5(user.AsSpan(0, size), ms);
                        var userKey = Utility.IntParse(ms);
                        request.UserAgent.Span.CopyTo(user.AsSpan(size));
                        size += request.UserAgent.Length;
                        ms = user.AsSpan(size, 16);
                        Utility.MD5(user.AsSpan(0, size), ms);
                        var value = Utility.Parse36Encode(Utility.IntParse(ms));

                        if (System.Net.IPAddress.TryParse(request.UserHostAddress, out var iPAddress))
                        {
                            var SessionKey = new StringValue(Guid.NewGuid().ToByteArray());

                            var appId = Utility.Parse36Encode(Utility.IntParse(WebServlet.AppId.Span));
                            var username = $"{this.Context.Token.Username}@{appId}";
                            var did = BitConverter.GetBytes(device.Id.Value);
                            did.AsSpan(6).Reverse();
                            var port = device.Port.Value.StringValue();
                            port.Span.Reverse();

                            Utility.SyncClient(0x01, new StringValue(iPAddress.GetAddressBytes()), new StringValue(username), new StringValue(did, 2, 6), SessionKey, port.Slice(2));

                            this.Context.Send("Socks5.Mapper", new WebMeta().Put("port", BitConverter.ToUInt16(did.AsSpan(6, 2))).Put("ip", device.Ip).Put("host", request.Url.Host).Put("repost", $"{device.Id}@{request.Url.Host}", "user", username, "session", Convert.ToBase64String(SessionKey.Span)), true);
                        }
                    }
                    finally
                    {
                        System.Buffers.ArrayPool<byte>.Shared.Return(user);
                    }

                }
                break;
            case "Proxy":
                {
                    var proxyUI = UISection.Create(new UITitle("代理参数"));
                    var user = System.Buffers.ArrayPool<byte>.Shared.Rent(520);
                    try
                    {
                        if (System.Net.IPAddress.TryParse(request.UserHostAddress, out var iPAddress))
                        {
                            var did = BitConverter.GetBytes(device.Id.Value);
                            did.AsSpan(6).Reverse();
                            did.AsSpan(2).CopyTo(user);
                            var username = $"{this.Context.Token.Username}@{request.Url.Host}";
                            var size = username.WriteBytes(user, 6) + 6;
                            iPAddress.TryWriteBytes(user.AsSpan(size), out var bytesWritten);
                            size += bytesWritten;

                            WebServlet.AppSecret.Span.CopyTo(user.AsSpan(size));
                            size += 16;
                            var ms = user.AsSpan(size, 16);
                            Utility.MD5(user.AsSpan(0, size), ms);
                            var pwd = user.AsSpan(size + 16);

                            System.Buffers.Binary.BinaryPrimitives.WriteInt32BigEndian(pwd, Utility.IntParse(ms));

                            var port3 = device.Port.Value.StringValue();
                            port3.Span.Reverse();
                            port3.Slice(2).Span.CopyTo(pwd.Slice(4));


                            var value = Utility.ToBase64String(pwd.Slice(0, 6));

                            Utility.SyncClient(0x01, new StringValue(iPAddress.GetAddressBytes()), new StringValue(username), new StringValue(did, 2, 6), new StringValue(value), port3.Slice(2));


                            var port = BitConverter.ToUInt16(BitConverter.GetBytes(device.Id.Value).AsSpan(6, 2));
                            proxyUI.AddCell("资源网址", $"{device.Ip}:{port}", new UIClick($"{device.Ip}:{port}") { Key = "Copy" })
                            .NewSection().AddCell("服务器", $"{request.Url.Host}:443", new UIClick($"{request.Url.Host}:443") { Key = "Copy" })
                            .AddCell("账号", "点击复制", new UIClick(username) { Key = "Copy" })
                            .AddCell("密码", "点击复制", new UIClick(value) { Key = "Copy" })
                            .Header.Put("text", "Socks5代理");

                            proxyUI.SendTo(this.Context);
                        }
                    }
                    finally
                    {
                        System.Buffers.ArrayPool<byte>.Shared.Return(user);
                    }
                    //   t

                }
                break;
            case "Editer":
                {
                    var config = this.AsyncDialog("Settings", g =>
                    {
                        var from = new Web.UIFormDialog() { Title = "设备" };
                        from.AddTextValue().Put("登录地址", $"{device.Ip}:{device.Port}").Put("用户名", device.Username);

                        from.AddText("名称", "Caption", device.Caption);

                        from.AddText("描述", "Desc", device.Desc).NotRequired();//.Put("tip", String.Empty);
                        from.Submit("确认修改", $"{this.Context.Request.Model}.{this.Context.Request.Command}");
                        return from;
                    });
                    Data.HotCache.Put(new Entities.Device
                    {
                        Id = device.Id,
                        Desc = config["Desc"],
                        Caption = config["Caption"]
                    });
                    this.Context.Send($"{this.Context.Request.Model}.{this.Context.Request.Command}", true);

                }
                break;
            case "UploadFile":
                if (request.IsApp)
                {
                    request.Arguments["Model"] = "File";
                    goto case "Dir";
                }
                else
                {
                    this.Context.Send("UploadFile", new WebMeta().Put("Path", Path), true);
                }
                break;
            case "Dir":
            case "File":
                {
                    var media_id = this.AsyncDialog("media_id", g =>
                      {
                          if (request.IsApp)
                          {
                              return Web.UIDialog.Create("File");
                          }
                          else
                          {
                              var from = new Web.UIFormDialog() { Title = "上传文件" };
                              var conf = from.AddFile("选择资源", "media_id", String.Empty).Put("Accept", "*/*").Put("Multiple", true);

                              switch (model)
                              {
                                  case "Dir":
                                      from.Title = "上传文件夹";
                                      conf.Put("Dir", true);
                                      break;
                              }
                              from.Submit("确认上传");
                              return from;
                          }
                      });
                    var deviceKey = Utility.Guid(this.AsyncDialog("Device", "none"));
                    var filePath = String.Format("{0}{1}", Path, Path.EndsWith('/') ? "" : "/");
                    if (media_id.StartsWith("http://") || media_id.StartsWith("https://"))
                    {
                        var url = new Uri(media_id);
                        var name = Uri.UnescapeDataString(url.AbsolutePath.Substring(url.AbsolutePath.LastIndexOf('/') + 1));

                        url.WebRequest().Get(r =>
                        {
                            if (r.StatusCode == System.Net.HttpStatusCode.OK)
                            {
                                var tempFile = System.IO.Path.GetTempFileName();
                                var stream = System.IO.File.Open(tempFile, System.IO.FileMode.Create);

                                r.ReadAsData((b, i, c) =>
                                {
                                    if (c == 0 && b.Length == 0)
                                    {
                                        if (i == -1)
                                        {
                                            this.Prompt("Web SSH", "上传失败", false);
                                            stream.Close();
                                            System.IO.File.Delete(tempFile);
                                        }
                                        else
                                        {
                                            stream.Flush();
                                            stream.Close();
                                            try
                                            {
                                                Upload(name, filePath, tempFile, device, password, deviceKey);
                                                this.Prompt("上传成功", false);
                                            }
                                            catch (Exception ex)
                                            {
                                                this.Prompt("上传错误", ex.Message, false);
                                            }
                                        }
                                        this.Context.Send(false);
                                        this.Context.OutputFinish();
                                    }
                                    else
                                    {
                                        stream.Write(b, i, c);
                                    }
                                });
                            }
                            else
                            {

                                this.Prompt("Web SSH", "上传失败", false);
                                this.Context.OutputFinish();
                            }
                        });
                        response.Redirect(Empty);
                    }
                    else
                    {
                        media_id = Uri.UnescapeDataString(media_id);
                        var filename = UMC.Data.Reflection.ConfigPath(String.Format("Static\\TEMP\\{0}", media_id.Substring(media_id.IndexOf('/', 2) + 1)));

                        var name = media_id.Substring(media_id.LastIndexOf('/') + 1);
                        try
                        {
                            Upload(name, filePath, filename, device, password, deviceKey);
                        }
                        catch (Exception ex)
                        {
                            this.Prompt("上传错误", ex.Message);
                        }
                        this.Context.Send(true);
                    }

                }
                break;
            case "OpenFile":
                {

                    var Type = this.AsyncDialog("Type", "none");
                    var n = Path.LastIndexOf('/');
                    var name = Path.Substring(n + 1);
                    String cmd = String.Empty; ;
                    switch (this.AsyncDialog("Type", "none"))
                    {
                        case "1":
                            cmd = $"ps aux |grep {name}";
                            break;
                        case "2":
                            if (name.EndsWith(".zip"))
                            {
                                cmd = $"unzip {name}";
                            }
                            else if (name.EndsWith(".rar"))
                            {
                                cmd = $"unrar {name}";
                            }
                            else if (name.EndsWith(".tar.gz"))
                            {

                                cmd = $"tar -xzvf {name}";

                            }
                            else if (name.EndsWith(".tar.bz2"))
                            {

                                cmd = $"tar -xjvf {name}";
                            }
                            else if (name.EndsWith(".tar"))
                            {

                                cmd = $"tar -xvf {name}";

                            }
                            break;
                        case "3":
                            cmd = $"tar -czf {name}.tar.gz {name}";
                            break;
                    }

                    if (request.IsApp)
                    {

                        var url = new Uri(request.Url, $"/WebSSH/{device.Id}{Path.Substring(0, n + 1)}?cmd={Uri.EscapeDataString(cmd)}").AbsoluteUri;

                        var webMeta = new WebMeta();
                        webMeta.Put("value", url);
                        webMeta.Put("title", device.Caption);
                        webMeta.Put("right", new UIEventText().Icon('\uf11c').Click(UIClick.Click(new UIClick(request, "Model", "Keyboard"))));
                        this.Context.Send("Url", webMeta, true);
                    }
                    else
                    {
                        this.Context.Send("OpenPath", new WebMeta().Put("Path", Path.Substring(0, n + 1)).Put("Cmd", cmd), true);
                    }
                }
                break;
            case "Open":
                if (request.IsApp)
                {
                    String url;
                    if (Path == "/")
                    {
                        url = new Uri(request.Url, $"/WebSSH/{device.Id}/").AbsoluteUri;
                    }
                    else
                    {
                        url = new Uri(request.Url, $"/WebSSH/{device.Id}{Path}/").AbsoluteUri;

                    }
                    var webMeta = new WebMeta();
                    webMeta.Put("value", url);
                    webMeta.Put("title", device.Caption);
                    webMeta.Put("right", new UIEventText().Icon('\uf11c').Click(UIClick.Click(new UIClick(request, "Model", "Keyboard"))));
                    this.Context.Send("Url", webMeta, true);
                }
                else
                {
                    this.Context.Send("OpenPath", new WebMeta().Put("Path", Path), true);
                }
                break;
            case "Keyboard":
                {
                    var ui = this.AsyncDialog("UI", "none");
                    var Paste = this.AsyncDialog("PasteText", r =>
                      {
                          var s = new UISheetDialog() { Title = "快捷键" };

                          s.CloseEvent = $"{request.Model}.{request.Command}";
                          s.Cells(3);
                          s.Put(new UIClick("Event", new WebMeta().UIEvent("UI.Callback", ui, new WebMeta().Put("type", "Keyboard", "value", "\u001b"))) { Text = "ESC" });
                          s.Put(new UIClick("Event", new WebMeta().UIEvent("UI.Callback", ui, new WebMeta().Put("type", "Keyboard", "value", "\u001b[A"))) { Text = "↑" });
                          s.Put(new UIClick("Event", new WebMeta().UIEvent("UI.Callback", ui, new WebMeta().Put("type", "Keyboard", "value", "\u0003"))) { Text = "Ctrl + C" });
                          s.Put(new UIClick("Event", new WebMeta().UIEvent("UI.Callback", ui, new WebMeta().Put("type", "Keyboard", "value", "\u001b[D"))) { Text = "←" });
                          s.Put(new UIClick("Paste", new UIClick(request)) { Text = "粘贴" });
                          s.Put(new UIClick("Event", new WebMeta().UIEvent("UI.Callback", ui, new WebMeta().Put("type", "Keyboard", "value", "\u001b[C"))) { Text = "→" });
                          s.Put(new UIClick("Event", new WebMeta().UIEvent("UI.Callback", ui, new WebMeta().Put("type", "Keyboard", "value", "\u001b[H"))) { Text = "Home" });
                          s.Put(new UIClick("Event", new WebMeta().UIEvent("UI.Callback", ui, new WebMeta().Put("type", "Keyboard", "value", "\u001b[B"))) { Text = "↓" });
                          s.Put(new UIClick("Event", new WebMeta().UIEvent("UI.Callback", ui, new WebMeta().Put("type", "Keyboard", "value", "\u001b[F"))) { Text = "END" });

                          return s;
                      });
                    this.Context.Send(new WebMeta().UIEvent("UI.Callback", ui, new WebMeta().Put("type", "Keyboard", "value", Paste)), true);
                }
                break;
            case "New":
                {
                    var filePath = String.Format("{0}{1}", Path, Path.EndsWith('/') ? "" : "/");
                    var dir = this.AsyncDialog("DirName", r => new UITextDialog() { Title = "新建文件夹" });
                    using (var sftp = new SftpClient(new PasswordConnectionInfo(device.Ip, device.Port ?? 22, device.Username, password)))
                    {
                        sftp.Connect();

                        sftp.CreateDirectory(filePath + dir);

                    }
                    this.Context.Send(true);
                }
                break;
            case "NewFile":
                {
                    var filePath = String.Format("{0}{1}", Path, Path.EndsWith('/') ? "" : "/");
                    var dir = this.AsyncDialog("FileName", r => new UITextDialog() { Title = "新建文件名" });
                    request.Arguments["Path"] = filePath + dir;

                    this.Context.Send(UIClick.Markdown(new UIClick(request, "Model", "Content")), true);//"Markdown", new WebMeta().Put("submit", new UIClick(request, "Model", "Content")), true);
                }
                break;
            case "Download":
                response.Redirect(new Uri(request.Url, $"/WebSSH/{device.Id}{Path}"));
                break;
            case "Edit":
                this.Context.Send("Markdown", new WebMeta().Put("submit", new UIClick(request, "Model", "Content")), true);
                break;
            case "Share":
                var d = Utility.Guid(this.Context.Token.Device.Value);
                var bv = Utility.DES(d, Utility.Guid(Web.WebActivity.TempKey).Value);
                var secretKey = Utility.MD5(d, Web.WebActivity.TempKey);
                var code = new Totp(secretKey, 30, OtpHashMode.Sha1, 6).ComputeTotp();

                var we = new WebMeta().Put("url", new Uri(request.Url, $"/WebSSH/{device.Id}{Path}?d={Utility.ToBase64String(bv)}&t={code}").AbsoluteUri);
                we.Put("title", "Web SSH文件下载");
                we.Put("desc", "30秒之内有效");
                we.Put("src", "https://www.apiumc.com/css/images/icon/webssh.png");
                this.Context.Send("Share", we, true);
                break;
            case "Down":
            case "View":
                this.AsyncDialog("View", r =>
                {
                    var value = UIClick.Markdown(new UIClick(request, "Model", "Content"));
                    value.Text = "打开";
                    var s = new UISheetDialog() { Title = "文件选择" };

                    s.Cells(3);

                    s.Put(value);
                    if (request.IsApp)
                    {
                        s.Put(new UIClick(request, "Model", "Share") { Text = "下载" });
                    }
                    else
                    {
                        s.Put(new UIClick(new Uri(request.Url, $"/WebSSH/{device.Id}{Path}").AbsoluteUri) { Key = "Url", Text = "下载" });
                    }
                    s.Put(new UIClick(request, "Model", "Info") { Text = "属性" });
                    s.Put(new UIClick(request, "Model", "Rename") { Text = "重命名" });
                    s.Put(new UIClick(request, "Model", "Copy") { Text = "复制" });
                    if (Path.EndsWith(".zip") || Path.EndsWith(".rar") || Path.EndsWith(".tar") || Path.EndsWith(".tar.gz") || Path.EndsWith(".tar.bz2"))
                    {
                        s.Put(new UIClick(request, "Model", "OpenFile", "Type", "2") { Text = "解压" });
                    }
                    else
                    {
                        s.Put(new UIClick(request, "Model", "OpenFile", "Type", "3") { Text = "压缩" });
                    }
                    s.Put(new UIClick(request, "Model", "Exe") { Text = "运行" });
                    s.Put(new UIClick(request, "Model", "BgExe") { Text = "后台运行" });
                    s.Put(new UIClick(request, "Model", "OpenFile", "Type", "1") { Text = "相关进程" });



                    return s;
                });
                break;
            case "Info":
                {
                    using (var sftp = new SftpClient(new PasswordConnectionInfo(device.Ip, device.Port ?? 22, device.Username, password)))
                    {
                        sftp.Connect();
                        var file = sftp.Get(Path);

                        var title = new UITitle("文件属性");
                        var ui = UMC.Web.UISection.Create(title);// new UITitle("关于应用"));

                        title.Style.BgColor(0x0eaee3);
                        title.Style.Color(0xfff);

                        var header = new UIHeader();
                        var style = new UIStyle();
                        style.BgColor(0x0eaee3).
                        Align(1).Color(0xfff).Padding(20, 20).Size(12).Name("icon", new UIStyle().Font("wdk").Size(60));
                        header.Desc(new WebMeta("desc", file.Name).Put("icon", "\uf298"), "{icon}\n{desc}", style);

                        ui.UIHeader = header;
                        String fType = "普通文件";
                        if (file.IsCharacterDevice)
                        {
                            fType = "字符设备文件";

                        }
                        if (file.IsDirectory)
                        {
                            fType = "目录文件";
                        }
                        else if (file.IsBlockDevice)
                        {

                            fType = "块设备文件";
                        }
                        else if (file.IsNamedPipe)
                        {

                            fType = "管道文件";
                        }
                        else if (file.IsSymbolicLink)
                        {
                            fType = "链接文件";
                        }
                        ui.AddCell("类型", fType).AddCell("大小", Utility.GetBitSize(file.Length)).AddCell("路径", Path);

                        ui.NewSection().AddCell("运行权限", file.OwnerCanExecute ? "有" : "无").AddCell("可读权限", file.OwnerCanRead ? "有" : "无").AddCell("可写权限", file.OwnerCanWrite ? "有" : "无").NewSection().AddCell("更新时间", Utility.GetDate(file.LastWriteTime));
                        ui.SendTo(this.Context);
                    }
                }
                break;
            case "Copy":
                {
                    var n = Path.LastIndexOf('/');
                    var name = Path.Substring(n + 1);
                    Path = Path.Substring(0, n + 1);
                    var nIndex = name.IndexOf('.');
                    var nName = string.Empty;
                    int time = 1;
                    using (var sftp = new SftpClient(new PasswordConnectionInfo(device.Ip, device.Port ?? 22, device.Username, password)))
                    {
                        sftp.Connect();
                        if (nIndex > -1)
                        {

                            nName = $"{name.Substring(0, nIndex)}_{time}{name.Substring(nIndex)}";
                            while (sftp.Exists(nName))
                            {
                                time++;

                                nName = $"{name.Substring(0, nIndex)}_{time}{name.Substring(nIndex)}";
                            }

                        }
                        else
                        {
                            nName = $"{name}_{time}";
                            while (sftp.Exists(nName))
                            {
                                time++;

                                nName = $"{name}_{time}";
                            }
                        }
                    }
                    String cmd = $"cp {name} \"{nName}\"";
                    if (request.IsApp)
                    {

                        var url = new Uri(request.Url, $"/WebSSH/{device.Id}{Path}?cmd={Uri.EscapeDataString(cmd)}").AbsoluteUri;

                        var webMeta = new WebMeta();
                        webMeta.Put("value", url);
                        webMeta.Put("title", device.Caption);
                        webMeta.Put("right", new UIEventText().Icon('\uf11c').Click(UIClick.Click(new UIClick(request, "Model", "Keyboard"))));
                        this.Context.Send("Url", webMeta, true);
                    }
                    else
                    {
                        this.Context.Send("OpenPath", new WebMeta().Put("Path", Path).Put("Cmd", cmd), true);
                    }

                }
                break;
            case "BgExe":
                {
                    var n = Path.LastIndexOf('/');
                    var fName = Path;
                    var name = Path.Substring(n + 1);
                    Path = Path.Substring(0, n + 1);

                    var nIndex = name.IndexOf('.');
                    var cmd = string.Empty;
                    if (name.EndsWith(".dll"))
                    {
                        cmd = $"nohup dotnet {name} > {name}.log 2>&1 &";
                    }
                    else if (name.EndsWith(".jar"))
                    {
                        cmd = $"nohup java -jar {name} > {name}.log 2>&1 &";
                    }
                    else if (name.EndsWith(".py"))
                    {
                        cmd = $"nohup python {name} > {name}.log 2>&1 &";
                    }
                    else if (name.EndsWith(".js"))
                    {
                        cmd = $"nohup node {name} > {name}.log 2>&1 &";
                    }
                    else
                    {
                        cmd = $"nohup ./{name} > {name}.log 2>&1 &";

                        using (var sftp = new SftpClient(new PasswordConnectionInfo(device.Ip, device.Port ?? 22, device.Username, password)))
                        {
                            sftp.Connect();

                            var file = sftp.Get(fName);
                            if (file.OwnerCanExecute == false)
                            {
                                this.AsyncDialog("Confirm", r => new UIConfirmDialog($"{name}文件无运行权限，是否授权?"));
                                sftp.ChangePermissions(fName, 777);
                                SSHLog(this.Context.Client.Context, device, $"chmod 777 {fName}");
                            }
                        }
                    }
                    if (request.IsApp)
                    {

                        var url = new Uri(request.Url, $"/WebSSH/{device.Id}{Path}?cmd={Uri.EscapeDataString(cmd)}").AbsoluteUri;
                        var webMeta = new WebMeta();
                        webMeta.Put("value", url);
                        webMeta.Put("title", device.Caption);
                        webMeta.Put("right", new UIEventText().Icon('\uf11c').Click(UIClick.Click(new UIClick(request, "Model", "Keyboard"))));
                        this.Context.Send("Url", webMeta, true);
                    }
                    else
                    {
                        this.Context.Send("OpenPath", new WebMeta().Put("Path", Path).Put("Cmd", cmd), true);
                    }
                }
                break;

            case "Exe":
                {
                    var n = Path.LastIndexOf('/');
                    var fName = Path;
                    var name = Path.Substring(n + 1);
                    Path = Path.Substring(0, n + 1);

                    var nIndex = name.IndexOf('.');
                    var cmd = string.Empty;

                    if (name.EndsWith(".dll"))
                    {
                        cmd = $"dotnet {name}";
                    }
                    else if (name.EndsWith(".jar"))
                    {
                        cmd = $"java -jar {name}";
                    }
                    else if (name.EndsWith(".py"))
                    {
                        cmd = $"python {name}";
                    }
                    else if (name.EndsWith(".js"))
                    {
                        cmd = $"node {name}";
                    }
                    else
                    {
                        cmd = $"./{name}";

                        using (var sftp = new SftpClient(new PasswordConnectionInfo(device.Ip, device.Port ?? 22, device.Username, password)))
                        {
                            sftp.Connect();

                            var file = sftp.Get(fName);
                            if (file.OwnerCanExecute == false)
                            {
                                this.AsyncDialog("Confirm", r => new UIConfirmDialog($"{name}文件无运行权限，是否授权?"));
                                sftp.ChangePermissions(fName, 777);
                                SSHLog(this.Context.Client.Context, device, $"chmod 777 {fName}");
                            }
                        }
                    }
                    if (request.IsApp)
                    {

                        var url = new Uri(request.Url, $"/WebSSH/{device.Id}{Path}?cmd={Uri.EscapeDataString(cmd)}").AbsoluteUri;
                        var webMeta = new WebMeta();
                        webMeta.Put("value", url);
                        webMeta.Put("title", device.Caption);
                        webMeta.Put("right", new UIEventText().Icon('\uf11c').Click(UIClick.Click(new UIClick(request, "Model", "Keyboard"))));
                        this.Context.Send("Url", webMeta, true);
                    }
                    else
                    {
                        this.Context.Send("OpenPath", new WebMeta().Put("Path", Path).Put("Cmd", cmd), true);
                    }

                }
                break;
            case "Rename":
                {
                    var ui = this.AsyncDialog("UI", "none");
                    var n = Path.LastIndexOf('/') + 1;
                    var name = Path.Substring(n);
                    var Rename = this.AsyncDialog("Rename", r => new UITextDialog() { Title = "重命名", DefaultValue = name });
                    using (var sftp = new SftpClient(new PasswordConnectionInfo(device.Ip, device.Port ?? 22, device.Username, password)))
                    {
                        sftp.Connect();
                        sftp.RenameFile(Path, Path.Substring(0, n) + Rename);
                    }

                    SSHLog(this.Context.Client.Context, device, $"mv {Path} {Path.Substring(0, n) + Rename}");

                    // this.Context.Send("UploadFile", new WebMeta().Put("Path", Path), true);
                    this.Context.UIEvent("Search", ui, new WebMeta("key", "Path").Put("search", new WebMeta().Put("Path", Path.Substring(0, n))), true);
                }
                break;
            case "Content":
                {
                    using (var sftp = new SftpClient(new PasswordConnectionInfo(device.Ip, device.Port ?? 22, device.Username, password)))
                    {
                        sftp.Connect();

                        var Content = this.AsyncDialog("Content", r =>
                        {

                            String s = String.Empty;
                            try
                            {
                                if (sftp.Exists(Path))
                                {
                                    var file = sftp.Get(Path);
                                    if (file.Length < 10000000)
                                    {
                                        s = sftp.ReadAllText(Path);
                                    }
                                    else
                                    {
                                        s = "文件已经超过1M，请下载后再查看";
                                    }
                                }

                            }
                            catch //(Exception ex)
                            {
                                // this.Prompt("打开失败", ex.Message);
                            }
                            response.Redirect(new WebMeta().Put("Content", s).Put("title", Path));



                        });
                        if (sftp.Exists(Path))
                        {
                            var file = sftp.Get(Path);
                            if (file.Length >= 10000000)
                            {
                                this.Prompt("原文件已经超过1M，需要先删除后，才可在线保存");
                            }
                            // sftp.RenameFile
                            sftp.DeleteFile(Path);
                        }
                        sftp.WriteAllText(Path, Content);

                        SSHLog(this.Context.Client.Context, device, $"write {Path}");
                    }
                }
                break;
            case "Remove":
                {
                    this.AsyncDialog("Confirm", r => new UIConfirmDialog("确认移除此设备吗"));
                    UMC.Data.HotCache.Delete(new Entities.Device { Id = Utility.UInt64Parse(Key, 0) });

                    this.Context.Loger.Info().Write($"删除了{device.Username}@{device.Ip}设备").End();
                    this.Context.Send($"{request.Model}.{request.Command}.Remove", true);
                }
                break;
            case "Del":
                {
                    using (var sftp = new SftpClient(new PasswordConnectionInfo(device.Ip, device.Port ?? 22, device.Username, password)))
                    {
                        sftp.Connect();
                        if (Path.EndsWith('/'))
                        {
                            var delPath = Path.Substring(0, Path.Length - 1);
                            sftp.DeleteDirectory(delPath);
                            SSHLog(this.Context.Client.Context, device, $"rmdir {delPath}");
                            var webMeta = new WebMeta(request.Arguments);

                            webMeta.Remove("Model");

                            var nameIndex = delPath.LastIndexOf('/');
                            webMeta.Put("Path", nameIndex == 0 ? "/" : delPath.Substring(0, nameIndex));
                            this.Context.Send("ViewPath", new WebMeta().Put("Path", webMeta["Path"]), false);
                            this.Context.UIEvent("Search", this.AsyncDialog("UI", "none"), new WebMeta("key", "Path").Put("search", webMeta), true);
                        }
                        else
                        {
                            sftp.Delete(Path);
                            SSHLog(this.Context.Client.Context, device, $"rm {Path}");
                        }
                    }
                }
                break;
        }
    }
    void Upload(string name, string path, string filename, Entities.Device device, string password, Guid? deviceKey)
    {
        var filePath = String.Format("{0}{1}", path, path.EndsWith('/') ? "" : "/", name);

        using (var sftp = new SftpClient(new PasswordConnectionInfo(device.Ip, device.Port ?? 22, device.Username, password)))
        {
            sftp.Connect();
            if (name.EndsWith(".umczip"))
            {
                var zipFileName = filePath + ".umc.zip";
                if (sftp.Exists(zipFileName))
                {
                    sftp.DeleteFile(zipFileName);
                }
                var now = Utility.TimeSpan();
                var zipFIle = File.OpenRead(filename);
                sftp.UploadFile(zipFIle, zipFileName, true, (v) =>
                {
                    if (deviceKey.HasValue)
                    {
                        var old = Utility.TimeSpan();
                        if (old - now > 0)
                        {
                            Host.HttpWebSocket.Send(deviceKey.Value, UMC.Data.JSON.Serialize(new WebMeta("type", "progress", "value", $"已上传{v * 100 / ((ulong)zipFIle.Length)}%")));
                            now = old;
                        }
                    }
                });
                Host.HttpWebSocket.Send(deviceKey.Value, UMC.Data.JSON.Serialize(new WebMeta("type", "progress", "value", "上传完成")));

                using (var ssh = new SshClient(device.Ip, device.Port.Value, device.Username, password))
                {
                    ssh.Connect();
                    ssh.RunCommand($"unzip -o -d {filePath} {zipFileName}");
                }

                sftp.DeleteFile(zipFileName);


                var fs = ZipFile.OpenRead(filename).Entries;

                foreach (var f in fs)
                {
                    if (f.Length > 0)
                    {
                        SSHLog(this.Context.Client.Context, device, $"upload {filePath + f.FullName}");
                    }
                }
            }
            else
            {
                using (var s = System.IO.File.OpenRead(filename))
                {
                    var file = filePath + name;
                    var now = Utility.TimeSpan();
                    if (sftp.Exists(file))
                    {
                        sftp.DeleteFile(file);
                    }
                    sftp.UploadFile(s, file, true, (v) =>
                    {
                        if (deviceKey.HasValue)
                        {
                            var old = Utility.TimeSpan();
                            if (old - now > 0)
                            {
                                Host.HttpWebSocket.Send(deviceKey.Value, UMC.Data.JSON.Serialize(new WebMeta("type", "progress", "value", $"{name} {v * 100 / ((ulong)s.Length)}%")));
                                now = old;
                            }
                        }
                    });

                    Host.HttpWebSocket.Send(deviceKey.Value, UMC.Data.JSON.Serialize(new WebMeta("type", "progress", "value", $"文件上传完成")));

                    SSHLog(this.Context.Client.Context, device, $"upload {filePath + name}");
                }
            }
            System.IO.File.Delete(filename);

        }
    }

    void Create()
    {
        if (this.Context.Request.IsMaster == false)
        {
            this.Prompt("只有管理员才能新增设备");
        }
        var type = Utility.Parse(this.AsyncDialog("Type", k => new UISheetDialog() { Title = "发布服务类型" }.Put("SSH连接", "2").Put("远程桌面", "1").Put("其他端口", "0")), DeviceType.Tcp);

        var config = this.AsyncDialog("Settings", g =>
        {
            var from = new Web.UIFormDialog() { Title = "发布设备资源" };
            from.AddTextValue().Put("资源类型", type.ToString());

            from.AddText("资源名称", "Caption", String.Empty);
            from.AddText("设备地址", "Ip", String.Empty).PlaceHolder("IP地址");
            from.AddText("设备端口", "Port", String.Empty);
            from.AddText("发布端口", "PostPort", String.Empty).NotRequired().PlaceHolder("默认与设备端口一致");
            switch (type)
            {
                case DeviceType.Ssh:
                    from.AddText("用户名", "Username", String.Empty).Put("tip", String.Empty);
                    from.AddPassword("密码", "Password");
                    break;
                case DeviceType.Rdp:
                    from.AddText("用户名", "Username", String.Empty).NotRequired().Put("tip", String.Empty);
                    from.AddPassword("密码", "Password").NotRequired();
                    break;
                default:
                    from.AddText("用户名", "Username", String.Empty).NotRequired().Put("tip", String.Empty);
                    from.AddPassword("密码", "Password").NotRequired();
                    // from.AddCheckBox("", "Tag", "0").Add("共享账户", "1");
                    break;
            }
            from.AddText("描述", "Desc", String.Empty).NotRequired().Put("tip", String.Empty);
            from.Submit("确认发布", $"{this.Context.Request.Model}.{this.Context.Request.Command}");
            return from;
        });
        if (System.Net.IPAddress.TryParse(config["Ip"], out var ip) == false || ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
        {
            this.Prompt("IP地址不正确");

        }
        var id = new byte[8];
        ip.TryWriteBytes(id.AsSpan(2), out var l);
        var Port = (ushort)Utility.IntParse(config["Port"], 22);
        var PostPort = (ushort)Utility.IntParse(config["PostPort"], Port);
        BitConverter.TryWriteBytes(id.AsSpan(6), PostPort);
        var deviceId = BitConverter.ToUInt64(id);
        if (UMC.Data.HotCache.Get(new Device { Id = deviceId }) != null)
        {
            this.Prompt("此IP的发布端口已存在");
        }
        var Tag = config["Tag"] ?? String.Empty;
        var device = new Entities.Device
        {
            Id = deviceId,
            Ip = config["Ip"],
            Port = Utility.IntParse(config["Port"], 22),
            Username = config["Username"],
            Desc = config["Desc"],
            Caption = config["Caption"],
            Tag = Tag.Contains("1") ? 1 : 0,
            Type = type,//Entities.DeviceType.Ssh
        };
        if (type == DeviceType.Ssh)
        {

            var ssh = new SshClient(device.Ip, device.Port.Value, device.Username, config["Password"]);
            try
            {
                ssh.Connect();
                ssh.Disconnect();
                UMC.Data.HotCache.Put(device);
                UMC.Data.DataFactory.Instance().Password(new Guid(Utility.MD5(device.Id.ToString(), device.Username)), config["Password"]);
                this.Prompt("新增成功", false);

            }
            catch (Exception ex)
            {
                this.Prompt("异常", ex.Message);
            }
        }
        else
        {

            UMC.Data.HotCache.Put(device);
            if (String.IsNullOrEmpty(config["Password"]) == false)
                UMC.Data.DataFactory.Instance().Password(new Guid(Utility.MD5(device.Id.ToString(), device.Username)), config["Password"]);

        }

        this.Context.Send($"{this.Context.Request.Model}.{this.Context.Request.Command}.Add", false);
        this.Context.Send($"{this.Context.Request.Model}.{this.Context.Request.Command}", true);
    }
}
